﻿using System;
using System.Collections.Generic;
using System.Drawing;
using System.IO;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows.Forms;

namespace Experimentor
{
    public abstract class SlideLayout : ICloneable
    {
        protected string _name;
        protected string _description;
        protected List<SlidePosition> _positions;

        public SlideLayout()
        {
            this._positions = new List<SlidePosition>();
        }

        public string Name
        {
            get { return this._name; }
            private set { this._name = value;  }
        }

        public string Description
        {
            get { return this._description; }
            private set { this._description = value; }
        }

        public List<SlidePosition> Positions
        {
            get { return this._positions; }
            private set { }
        }

        public abstract Panel doLayout(Rectangle parrect, string layoutArgs);

        public abstract void clearAllSlides();

        public abstract Control showSlide(string baseFile, string fileName, int position);

        public abstract void addUserActionControl(Control control, int position);

        public object Clone()
        {
            SlideLayout newLayout = (SlideLayout)this.MemberwiseClone();
            newLayout.Positions = new List<SlidePosition>();
            foreach (SlidePosition pos in this.Positions) newLayout.Positions.Add((SlidePosition)pos.Clone());
            return newLayout;
        }
    }

    public class SlideLayout_Single : SlideLayout
    {
        private Panel _curPanel;

        public SlideLayout_Single()
            : base()
        {
            this._name = "Single slide";
            this._description = "Position SINGlE: Only one position for one slide";
            this._positions.Add(new SlidePosition("Single"));
        }

        public override Panel doLayout(Rectangle parrect, string layoutArgs)
        {
            this._curPanel = new Panel();
            //TODO use layoutArgs
            this._curPanel.Size = new System.Drawing.Size(parrect.Width, parrect.Height);
            return this._curPanel;
        }

        public override void clearAllSlides()
        {
            this._curPanel.Controls.Clear();
        }

        public override Control showSlide(string baseFile, string fileName, int position)
        {
            string pathToFile = Path.Combine(Path.GetDirectoryName(baseFile), fileName);
            if (File.Exists(pathToFile))
            {
                Image image = Image.FromFile(pathToFile);
                PictureBox box = new PictureBox();
                box.Image = image;
                box.Size = new Size(image.Width, image.Height);
                box.Location = new Point(this._curPanel.Width / 2 - box.Width / 2, this._curPanel.Height / 2 - box.Height / 2);
                this._curPanel.Controls.Add(box);
                return box;
            }
            else return null;
        }

        public override void addUserActionControl(Control control, int position)
        {
            control.Location = new Point(this._curPanel.Width - 30 - control.Width, this._curPanel.Height - 30 - control.Height);
            this._curPanel.Controls.Add(control);
            control.BringToFront();
        }
    }

    public class SlideLayout_TopAndBottom : SlideLayout
    {
        private FlowLayoutPanel _curPanel;
        
        public SlideLayout_TopAndBottom()
            : base()
        {
            this._name = "Top and bottom slide";
            this._description = "Position TOP, Position BOTTOM: equal size";
            this._positions.Add(new SlidePosition("Top"));
            this._positions.Add(new SlidePosition("Bottom"));
        }

        public override Panel doLayout(Rectangle parrect, string layoutArgs)
        {
            this._curPanel = new FlowLayoutPanel();
            //TODO use layoutArgs
            this._curPanel.Size = new System.Drawing.Size(960, 720);
            Panel topPanel = new Panel();
            topPanel.Size = new System.Drawing.Size(960, 360);
            Panel bottomPanel = new Panel();
            bottomPanel.Size = new System.Drawing.Size(960, 360);
            this._curPanel.Controls.Add(topPanel);
            this._curPanel.Controls.Add(bottomPanel);
            return this._curPanel;
        }

        public override void clearAllSlides()
        {
            foreach (Control subpanel in this._curPanel.Controls) subpanel.Controls.Clear();
        }

        public override Control showSlide(string baseFile, string fileName, int position)
        {
            string pathToFile = Path.Combine(Path.GetDirectoryName(baseFile), fileName);
            if (File.Exists(pathToFile))
            {
                Image image = Image.FromFile(pathToFile);
                PictureBox box = new PictureBox();
                box.Image = image;
                box.Size = new Size(image.Width, image.Height);
                box.Location = new Point(this._curPanel.Controls[position].Width / 2 - box.Width / 2, this._curPanel.Controls[position].Height / 2 - box.Height / 2);
                this._curPanel.Controls[position].Controls.Add(box);
                return box;
            }
            else return null;
        }

        public override void addUserActionControl(Control control, int position)
        {
            control.Location = new Point(this._curPanel.Controls[position].Width / 2 - control.Width / 2, this._curPanel.Controls[position].Height / 2 - control.Height / 2);
            this._curPanel.Controls[position].Controls.Add(control);
        }
    }

    public class SlideLayout_CenterVsLeftRightRand : SlideLayout
    {
        private Panel _curCenter;
        private Panel _curLeft;
        private Panel _curRight;
        private Random rnd;

        public SlideLayout_CenterVsLeftRightRand()
            : base()
        {
            this._name = "Center vs. Left/Right-Random";
            this._description = "Position CENTER: if filled, uses the whole window; Position LEFT/RIGHT: equal size, uses whichever is free at random";
            this._positions.Add(new SlidePosition("Center"));
            this._positions.Add(new SlidePosition("Left/Right (random)"));
            this.rnd = new Random();
        }

        public override Panel doLayout(Rectangle parrect, string layoutArgs)
        {
            //TODO use layoutArgs
            this._curCenter = new Panel();
            this._curCenter.BackColor = Color.White;
            this._curCenter.Size = new System.Drawing.Size(parrect.Width, parrect.Height);
            this._curLeft = new Panel();
            this._curLeft.Size = new System.Drawing.Size(parrect.Width / 2, parrect.Height);
            this._curLeft.Location = new Point(0, 0);
            this._curRight = new Panel();
            this._curRight.Size = new System.Drawing.Size(parrect.Width / 2, parrect.Height);
            this._curRight.Location = new Point(parrect.Width / 2, 0);
            return this._curCenter;
        }

        public override void clearAllSlides()
        {
            this._curCenter.Controls.Clear();
            this._curLeft.Controls.Clear();
            this._curRight.Controls.Clear();
        }

        public override Control showSlide(string baseFile, string fileName, int position)
        {
            string pathToFile = Path.Combine(Path.GetDirectoryName(baseFile), fileName);
            if (File.Exists(pathToFile))
            {
                Image image = Image.FromFile(pathToFile);
                PictureBox box = new PictureBox();
                box.Image = image;
                box.Size = new Size(image.Width, image.Height);
                if (position == 0)
                {
                    box.Location = new Point(this._curCenter.Width / 2 - box.Width / 2, this._curCenter.Height / 2 - box.Height / 2);
                    this._curCenter.Controls.Add(box);
                }
                else
                {
                    Panel toinsert = (rnd.NextDouble() < 0.5 ? this._curLeft : this._curRight);
                    if (toinsert.Controls.Count > 0) toinsert = (toinsert == this._curLeft ? this._curRight : this._curLeft);
                    box.Location = new Point(toinsert.Width / 2 - box.Width / 2, toinsert.Height / 2 - box.Height / 2);
                    toinsert.Controls.Clear();
                    toinsert.Controls.Add(box);
                    if (!this._curCenter.Controls.Contains(this._curLeft)) this._curCenter.Controls.Add(this._curLeft);
                    if (!this._curCenter.Controls.Contains(this._curRight)) this._curCenter.Controls.Add(this._curRight);
                }
                return box;
            }
            else return null;
        }

        public override void addUserActionControl(Control control, int position)
        {
            if (position == 0)
            {
                control.Location = new Point(this._curCenter.Width / 2 - control.Width / 2, this._curCenter.Height / 2 - control.Height / 2);
                this._curCenter.Controls.Add(control);
            }
            else
            {
                Panel toinsert = (rnd.NextDouble() < 0.5 ? this._curLeft : this._curRight);
                if (toinsert.Controls.Count > 0) toinsert = (toinsert == this._curLeft ? this._curRight : this._curLeft);
                control.Location = new Point(toinsert.Width / 2 - control.Width / 2, toinsert.Height / 2 - control.Height / 2);
                toinsert.Controls.Clear();
                toinsert.Controls.Add(control);
                if (!this._curCenter.Controls.Contains(this._curLeft)) this._curCenter.Controls.Add(this._curLeft);
                if (!this._curCenter.Controls.Contains(this._curRight)) this._curCenter.Controls.Add(this._curRight);
            }
        }
    }

    public class SlideLayout_CenterVsTopBottomFixed : SlideLayout
    {
        private Panel _curCenter;
        private Panel _curTop;
        private Panel _curBottom;

        public SlideLayout_CenterVsTopBottomFixed()
            : base()
        {
            this._name = "Center vs. Top/Bottom";
            this._description = "Position CENTER: if filled, uses the whole window; Position TOP: upper half of windows; Position BOTTOM: lower half of window";
            this._positions.Add(new SlidePosition("Center"));
            this._positions.Add(new SlidePosition("Top"));
            this._positions.Add(new SlidePosition("Bottom"));
        }

        public override Panel doLayout(Rectangle parrect, string layoutArgs)
        {
            //TODO use layoutArgs
            this._curCenter = new Panel();
            this._curCenter.BackColor = Color.White;
            this._curCenter.Size = new System.Drawing.Size(parrect.Width, parrect.Height);
            this._curTop = new Panel();
            this._curTop.Size = new System.Drawing.Size(parrect.Width, parrect.Height/2);
            this._curTop.Location = new Point(0, 0);
            this._curBottom = new Panel();
            this._curBottom.Size = new System.Drawing.Size(parrect.Width, parrect.Height / 2);
            this._curBottom.Location = new Point(0, parrect.Height / 2);
            return this._curCenter;
        }

        public override void clearAllSlides()
        {
            this._curCenter.Controls.Clear();
            this._curTop.Controls.Clear();
            this._curBottom.Controls.Clear();
        }

        public override Control showSlide(string baseFile, string fileName, int position)
        {
            string pathToFile = Path.Combine(Path.GetDirectoryName(baseFile), fileName);
            if (File.Exists(pathToFile))
            {
                Image image = Image.FromFile(pathToFile);
                PictureBox box = new PictureBox();
                box.Image = image;
                box.Size = new Size(image.Width, image.Height);
                if (position == 0)
                {
                    box.Location = new Point(this._curCenter.Width / 2 - box.Width / 2, this._curCenter.Height / 2 - box.Height / 2);
                    this._curCenter.Controls.Add(box);
                }
                else
                {
                    Panel toinsert = (position==1 ? this._curTop : this._curBottom);
                    box.Location = new Point(toinsert.Width / 2 - box.Width / 2, toinsert.Height / 2 - box.Height / 2);
                    toinsert.Controls.Clear();
                    toinsert.Controls.Add(box);
                    if (!this._curCenter.Controls.Contains(this._curTop)) this._curCenter.Controls.Add(this._curTop);
                    if (!this._curCenter.Controls.Contains(this._curBottom)) this._curCenter.Controls.Add(this._curBottom);
                }
                return box;
            }
            else return (position == 0 ? this._curCenter : (position == 1 ? this._curTop : this._curBottom));
        }

        public override void addUserActionControl(Control control, int position)
        {
            if (position == 0)
            {
                control.Location = new Point(this._curCenter.Width / 2 - control.Width / 2, this._curCenter.Height / 2 - control.Height / 2);
                this._curCenter.Controls.Add(control);
            }
            else
            {
                Panel toinsert = (position == 1 ? this._curTop : this._curBottom);
                control.Location = new Point(toinsert.Width / 2 - control.Width / 2, toinsert.Height / 2 - control.Height / 2);
                toinsert.Controls.Clear();
                toinsert.Controls.Add(control);
                if (!this._curCenter.Controls.Contains(this._curTop)) this._curCenter.Controls.Add(this._curTop);
                if (!this._curCenter.Controls.Contains(this._curBottom)) this._curCenter.Controls.Add(this._curBottom);
            }
        }
    }

    public class SlidePosition : ICloneable
    {
        public string name;

        public SlidePosition (string name)
        {
            this.name = name;
        }

        public object Clone()
        {
            SlidePosition newpos = (SlidePosition)this.MemberwiseClone();
            return newpos;
        }
    }
}
